/*
 * Copyright (c) 2022  by Junzhao
 * THIS FILE IS PART OF JAVASE Song Huongkang PROJECT
 * All Rights Reserved.
 */

package 引用;

import org.junit.Test;
import 示例类.Employee;

import java.util.Comparator;
import java.util.function.*;

/**
 * @Description 引用
 * 方法引用
 * 什么时候使用呢？
 * 当 要传递给 Lambda 体的操作，已经有实现的方法了，可以使用方法引用！
 * 方法引用可以看做是 Lambda 表达式深层次的表达。换句话说，方法 引用就
 * 是 Lambda 表达式 ，也就是 函数式接口的一个实例，通过方法的名字来指向
 * 一个方法，可以认为是 Lambda 表达式的一个语法糖。
 * 要求 实现 接口的抽象方法 的参数列表和返回值类型，必须与方法引用的
 * 方法的参数列表和返回值类型保持一致！
 * <p>
 * 格式 使用操作符“::” 将类 或对象 ) 与 方法名分隔开来。
 * 如下三种主要使用情况
 * 对象::实例方法名
 * 类::静态方法名
 * 类::实例方法名
 * <p>
 * 构造器引用
 * 格式： ClassName::new
 * 与函数式接口相结合，自动与函数式接口中方法兼容。
 * 可以把构造器引用赋值给定义的方法，要求构造器参数列表要与接口中抽象方法的参数列表一致！
 * 且方法的返回值即为构造器对应类的对象。
 * <p>
 * 数组引用
 * 格式： type[] :: new
 * @Author 俊昭
 * @Date 2022/5/12
 */
public class ReferenceTest {
    /**
     * 方法引用
     */
    @Test
    public void test00() {

        // 情况一 对象::实例方法名
        Consumer<String> con1 = a -> System.out.println(a);// out 是一个全局对象
        Consumer<String> con2 = System.out::println;

        Employee emp = new Employee(1001, "bjz", 20, 15000);

        Supplier<String> s1 = () -> emp.getName();
        Supplier<String> s2 = emp::getName;

        System.out.println(s2.get());

        // 情况二 类::静态方法名
        Comparator<Integer> com1 = (o1, o2) -> o1 > o2 ? 1 : 0;
        Comparator<Integer> com2 = Integer::compareTo;

        // 情况三 类::实例方法名
        // 注意：当函数式接口方法的第一个参数是需要引用方法的调用者，
        // 并且第二个参数是需要引用方法的参数(或无参数)时：ClassName::methodName

        BiPredicate<String, String> equal1 = (s11, s12) -> s11.equals(s12);
        BiPredicate<String, String> equal2 = String::equals;

    }

    /**
     * 构造器引用 数组引用
     */
    @Test
    public void test002() {
        // Supplier<T>                 T get();
        Supplier<Employee> s1 = () -> new Employee();
        Supplier<Employee> s2 = Employee::new;

        // Function<T, R>             R apply(T t);
        Function<Integer, Employee> f1 = (i) -> new Employee(i);
        Function<Integer, Employee> f2 = Employee::new;

        // BiFunction<T, U, R>        R apply(T t, U u);
        BiFunction<Integer, String, Employee> b1 = (i, s) -> new Employee(i, s);
        BiFunction<Integer, String, Employee> b2 = Employee::new;


        // Function<T, R>             R apply(T t);
        Function<Integer,String[]> ff1 = integer -> new String[integer];
        Function<Integer,String[]> ff2 = String[]::new;
    }

}
